package model.macro
{
	import events.BattleEvent;
	import events.WorldEvent;
	import flash.events.EventDispatcher;
	import model.micro.Battle;
	import util.Random;
	import view.macro.MapSprite;
	
	/**
	 * The top level model component of the macro game.
	 */
	public class World extends EventDispatcher
	{
		/** A list of all the territories on the map */
		public var territories:Vector.<Territory>;
		/** A list of the players */
		public var players:Vector.<Player>;
		/** The name of the world. This might be unnecessary. */
		public var name:String;
		/** Number of turns gone by */
		public var turn:int;
		/** The player whose turn it is */
		private var _current_player:Player;
		
		/**
		 * Create a new world.
		 */
		public function World(territory_list:Vector.<Territory> = null, players_list:Vector.<Player> = null, world_name:String = "", current_player_turn:Player = null, seed_turn:int = 1)
		{
			turn = seed_turn;
			players = players_list;
			_current_player = current_player_turn;
			territories = territory_list;
			
			dispatchEvent(new WorldEvent(WorldEvent.TURN_BEGIN, this));
		}
		
		/**
		 * @return	The player whose turn it is
		 */
		public function get current_player():Player
		{
			return _current_player;
		}
		
		/**
		 * Advance to the next player's turn.
		 */
		public function nextTurn():void
		{
			// end turn
			dispatchEvent(new WorldEvent(WorldEvent.TURN_END, this));
			updatePlayerTerritoryLists();
			
			// begin next turn
			turn++;
			trace("turn " + turn);
			_current_player = players[(players.indexOf(_current_player) + 1) % players.length];
			
			dispatchEvent(new WorldEvent(WorldEvent.TURN_BEGIN, this));
			
			// update territories
			for each (var territory:Territory in territories)
			{
				if (territory.owner != null)
				{
					for each (var building:Building in territory.buildings)
					{
						var gold_to_add:int = building.gold_per_turn;
						territory.owner.gold += gold_to_add;
						dispatchEvent(new WorldEvent(WorldEvent.CHANGE_GOLD, this, [territory.owner, gold_to_add]));
					}
				}
				
				// update units
				for each (var unit:Unit in territory.units)
				{
					unit.morale = 1.0;
					unit.moves_remaining = 1;
				}
			}
		}
		
		private function updatePlayerTerritoryLists():void
		{
			for each (var player:Player in players)
			{
				player.territories = new Vector.<Territory>();
			}
			
			for each (var territory:Territory in territories)
			{
				if (territory.owner != null)
				{
					territory.owner.territories.push(territory);
				}
			}
		}
		
		/**
		 * Moves a unit from one territory to another.
		 * @param	from_territory	The territory the unit is in
		 * @param	unit			The unit
		 * @param	to_territory	The territory to move to
		 */
		public function moveUnit(from_territory:Territory, unit:Unit, to_territory:Territory):void
		{
			if (unit.moves_remaining <= 0)
			{
				throw new Error("Unit has no moves remaining");
			}
			if (unit.owner != _current_player)
			{
				throw new Error("You do not control that unit");
			}
			transferUnit(from_territory, unit, to_territory);
			unit.moves_remaining -= 1;
		}
		
		/**
		 * Move a group of units from one territory to another.
		 * @param	from_territory
		 * @param	moving_units
		 * @param	to_territory
		 */
		public function moveUnits(from_territory:Territory, moving_units:Vector.<Unit>, to_territory:Territory):void
		{
			trace("MOVING UNITS " + moving_units + " from " + from_territory + " to " + to_territory);
			if (moving_units.length > 0 && from_territory.owner.isHostile(to_territory.owner))
			{
				dispatchEvent(new WorldEvent(WorldEvent.BATTLE_BEGIN, this, {attackingTerritory: from_territory, defendingTerritory: to_territory, attackingPlayer: from_territory.owner, attackingUnits: moving_units}));
				
			}
			else
			{
				for each (var unit:Unit in moving_units)
				{
					moveUnit(from_territory, unit, to_territory);
				}
				dispatchEvent(new WorldEvent(WorldEvent.UNITS_MOVED, this, {"from": from_territory, "to": to_territory}));
			}
		}
		
		public function transferUnits(from_territory:Territory, moving_units:Vector.<Unit>, to_territory:Territory):void
		{
			for each (var unit:Unit in moving_units)
			{
				transferUnit(from_territory, unit, to_territory);
			}
			dispatchEvent(new WorldEvent(WorldEvent.UNITS_MOVED, this, {"from": from_territory, "to": to_territory}));
		}
		
		public function transferUnit(from_territory:Territory, unit:Unit, to_territory:Territory):void
		{
			from_territory.units.splice(from_territory.units.indexOf(unit), 1);
			to_territory.units.push(unit);
		}
	}
}